﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace XMLScript
{
    public class Utility
    {
        public static object InvokeMethod(string assemblyPath, string typeName, string methodName, params object[] parameters)
        {
            Assembly assembly = Assembly.LoadFrom(assemblyPath);
            Type classType = assembly.GetType(typeName, true, false);
            object dynamicObj = Activator.CreateInstance(classType);

            if (dynamicObj != null)
            {
                MethodInfo invokedMethod = classType.GetMethod(methodName);
                if (invokedMethod != null)
                {
                    var info = invokedMethod.GetParameters();
                    for (int i = 0; i < parameters.Length; i++)
                    {
                        Type paramType = info[i].ParameterType;
                        parameters[i] = Convert.ChangeType(parameters[i], paramType);
                    }

                    return invokedMethod.Invoke(dynamicObj, parameters);
                }
            }

            return null;
        }
        public static Type GetMethodType(string assemblyPath, string typeName, string methodName)
        {
            Assembly assembly = Assembly.LoadFrom(assemblyPath);
            Type classType = assembly.GetType(typeName, true, false);
            object dynamicObj = Activator.CreateInstance(classType);

            if (dynamicObj != null)
            {
                MethodInfo invokedMethod = classType.GetMethod(methodName);
                if (invokedMethod != null)
                    return invokedMethod.ReturnType;
            }

            return null;
        }

        //Taken from gCode SL code -> gcodesl.googlecode.com
        #region Snippet
        static char[] m_op = { '+', '-', '*', '/' };//add, subtract, multiply, divide
        public static int EvaluateInt(string toParse)
        {
            int val = 0, temp;

            var elements = toParse.Split(m_op);
            if (elements.Length == 1)
                int.TryParse(toParse, out val);
            else if (elements.Length == 2 && toParse.Trim().StartsWith("-"))
                int.TryParse(toParse, out val);
            else
            {
                List<int> calc = new List<int>(), toRemove = new List<int>();
                for (int i = 0; i < elements.Length; i++)
                {
                    elements[i] = elements[i].Trim();
                    bool success = int.TryParse(elements[i], out temp);
                    if (!success)
                        temp = 0;
                    calc.Add(temp);
                }

                //order of operations
                string toOp = toParse;
                for (int i = 0; i < calc.Count - 1; i++)
                {
                    char op = toOp.Remove(toOp.IndexOf(elements[i]), elements[i].Length + 1).Trim()[0];
                    if (i != calc.Count - 1)
                        toOp = toOp.Substring(toOp.IndexOf(elements[i + 1].ToString()));
                    if (op == m_op[2])
                    {
                        calc[i] = calc[i] * calc[i + 1];
                        calc[i + 1] = calc[i];
                        toRemove.Add(i);
                    }
                    else if (op == m_op[3])
                    {
                        calc[i] = calc[i] / calc[i + 1];
                        calc[i + 1] = calc[i];
                        toRemove.Add(i);
                    }
                    else if (op != m_op[0] && op != m_op[1])
                        throw new Exception("Only addition, subtraction, multiplication, and division operations are supported.");
                }
                foreach (int index in toRemove)
                    calc.RemoveAt(index);
                toRemove = new List<int>();

                toOp = toParse;
                for (int i = 0; i < calc.Count - 1; i++)
                {
                    char op = toOp.Remove(toOp.IndexOf(elements[i]), elements[i].Length + 1).Trim()[0];
                    if (i != calc.Count - 1)
                        toOp = toOp.Substring(toOp.IndexOf(elements[i + 1].ToString()));
                    if (op == m_op[0])
                    {
                        calc[i] = calc[i] + calc[i + 1];
                        calc[i + 1] = calc[i];
                        toRemove.Add(i);
                    }
                    else if (op == m_op[1])
                    {
                        calc[i] = calc[i] - calc[i + 1];
                        calc[i + 1] = calc[i];
                        toRemove.Add(i);
                    }
                }
                foreach (int index in toRemove)
                    calc.RemoveAt(index);
                foreach (int no in calc)
                    val += no;
            }

            return val;
        }
        #endregion

        public int Add(params int[] numbers)
        {
            int toRet = 0;
            foreach (var num in numbers)
                toRet += num;
            return toRet;
        }
        public int Subtract(params int[] numbers)
        {
            if (numbers.Length == 0)
                return 0;
            else if (numbers.Length == 1)
                return numbers[1];
            int toRet = numbers[0];
            for (int i = 1; i < numbers.Length; i++)
                toRet -= numbers[i];
            return toRet;
        }
        public int Multiply(params int[] numbers)
        {
            if (numbers.Length == 0)
                return 0;
            int toRet = 1;
            foreach (var num in numbers)
                toRet *= num;
            return toRet;
        }
        public int Divide(params int[] numbers)
        {
            if (numbers.Length == 0)
                return 0;
            else if (numbers.Length == 1)
                return numbers[1];
            int toRet = numbers[0];
            for (int i = 1; i < numbers.Length; i++)
                toRet /= numbers[i];
            return toRet;
        }

        public bool LogicalAnd(params bool[] booleans)
        {
            if (booleans.Length == 0)
                return false;
            else if (booleans.Length == 1)
                return booleans[0];

            bool toRet = true;
            foreach (var boolean in booleans)
                toRet = toRet && boolean;
            return toRet;
        }
        public bool LogicalOr(params bool[] booleans)
        {
            if (booleans.Length == 0)
                return false;
            else if (booleans.Length == 1)
                return booleans[0];

            foreach (var boolean in booleans)
            {
                if (boolean)
                    return true;
            }
            return false;
        }
        public bool LogicalNot(bool alpha) { return !alpha; }
        public bool LogicalEquals(object alpha, object beta) { return alpha.Equals(beta); }

        public bool CompareGreaterThan(int alpha, int beta) { return alpha > beta; }
        public bool CompareLesserThan(int alpha, int beta) { return alpha < beta; }
        public bool CompareGreaterThanEqualTo(int alpha, int beta) { return alpha >= beta; }
        public bool CompareLesserThanEqualTo(int alpha, int beta) { return alpha <= beta; }

        public bool DeclareBool(bool alpha) { return alpha; }
        public int DeclareInt(int alpha) { return alpha; }
        public double DeclareDouble(double alpha) { return alpha; }
        public string DeclareString(string alpha) { return alpha; }

        public int RandomInt(int max)
        {
            return new Random().Next(max);
        }

        public void MessageBox(string text, string title) { System.Windows.Forms.MessageBox.Show(text, title); }
    }
}
